package com.liu.network.ip.bean;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

public class ReadGeoLiteCSV {
	private Map<Integer, String> cityLocationsMap = new HashMap<Integer, String>();
	private List<IPV4Info> ipv4List = new ArrayList<IPV4Info>();
	private String zipPath;
	private String zipName;
	private String cityLocationsName;
	private String IPV4Name;
	private String outputTxtPath;

	public ReadGeoLiteCSV(String zipPath, String zipName, String cityLocationsPath, String IPV4Path,
			String outputTxtPath) {
		this.zipName = zipName;
		this.zipPath = zipPath;
		this.cityLocationsName = cityLocationsPath;
		this.IPV4Name = IPV4Path;
		this.outputTxtPath = outputTxtPath;
	}

	@SuppressWarnings("resource")
	public void read() {
		System.out.println("地域文件名称：" + cityLocationsName);
		System.out.println("IP文件名称：" + IPV4Name);
		System.out.println("处理后的IP数据保存地址： " + outputTxtPath);
		boolean b = false;
		long time = System.currentTimeMillis();
		File file = new File(zipPath);
		InputStream cityLocationsInput = null;
		InputStream IPV4Input = null;
		ZipInputStream zipInput = null; // 定义压缩输入流
		ZipEntry entry = null; // 每一个压缩实体
		String entryName = "";
		String loadZipName = "";
		String fileName = "";
		int zipFileNum = 1;
		try {
			ZipFile zipFile = new ZipFile(file); // 实例化ZipFile对象
			zipInput = new ZipInputStream(new FileInputStream(file)); // 实例化ZIpInputStream
			while ((entry = zipInput.getNextEntry()) != null) { // 得到一个压缩实体
				entryName = entry.getName();
				int index = entryName.indexOf("/");
				fileName = entryName.substring(index + 1, entryName.length());
				System.out.println("zip文件:" + fileName);
				// 之前下载过并且下载的文件名称相等。那就不更新
				if (zipFileNum == 1) {
					loadZipName = entryName.substring(0, index);
					if (!"".equals(zipName) && zipName.equals(loadZipName)) {
						System.out.println("之前下载过" + zipName + "但是与现在下载的文件" + loadZipName + "相等;所有不更新IP库");
						return;
					} else {
						// 修改iplong配置文件
						updateProperties("ipLong.properties", "zipName", loadZipName);
					}
				}

				if (cityLocationsName.equals(fileName)) {
					cityLocationsInput = zipFile.getInputStream(entry); // 得到实体的输入流
				} else if (IPV4Name.equals(fileName)) {
					IPV4Input = zipFile.getInputStream(entry); // 得到实体的输入流
				}
				zipFileNum++;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("zip压缩包中共有" + zipFileNum + "个文件。");
		if (cityLocationsInput == null) {
			System.out.println("读取zip中的地域文件有误!!!");
			b = true;
		}
		if (IPV4Input == null) {
			System.out.println("读取zip中的IP文件有误!!!");
			b = true;
		}
		if (b) {
			return;
		}
		cityLocationsMap = readCityLocations(cityLocationsInput);
		ipv4List = readIPV4(IPV4Input);
		outTxt(outputTxtPath);
		System.out.println("读取IPLONG文件并输出耗时：" + (System.currentTimeMillis() - time) + "ms");
	}

	/**
	 * 修改properties文件中属性值对应的值 不修改其样式
	 * 
	 * @param propertiesName
	 *            properties文件名称
	 * @param propertity
	 *            属性名称
	 * @param value
	 *            属性值
	 */
	public void updateProperties(String propertiesName, String propertity, String value) {
		String basePath = this.getClass().getResource("/").getPath() + propertiesName;
		FileReader fr = null;
		BufferedReader bf = null;
		StringBuffer buf = new StringBuffer();
		try {
			fr = new FileReader(basePath);
			bf = new BufferedReader(fr);

			String line = null;
			while ((line = bf.readLine()) != null) {
				String cloneLine = line;
				if (line.trim().indexOf("#", 0) == 0) {
					buf.append(cloneLine);
				} else {
					String property = cloneLine.trim().split("=")[0];
					if (propertity.equals(property.trim())) {
						buf.append(property.trim() + " = " + value);
					} else {
						buf.append(cloneLine);
					}
				}
				buf.append(System.getProperty("line.separator"));
			}
		} catch (IOException e) {
			// 文件读取失败
			e.printStackTrace();
		} finally {
			if (bf != null) {
				try {
					bf.close();
				} catch (IOException e) {
					// 带缓冲的字符输入流关闭失败
					e.printStackTrace();
				}
			}
		}

		FileWriter fw = null;
		BufferedWriter bw = null;
		try {
			fw = new FileWriter(basePath);
			bw = new BufferedWriter(fw);
			bw.write(buf.toString());
		} catch (IOException e) {
			// 字符输出流类创建失败
			e.printStackTrace();
		} finally {
			if (bw != null) {
				try {
					bw.close();
				} catch (IOException e) {
					// 带缓冲的字符输出流关闭失败
					e.printStackTrace();
				}
			}
		}
		System.out.println("更新iplong配置文件;更新前zipName名称为:" + zipName + "更新后zipName名称为:" + value);

	}

	/**
	 * 读取城市名称及ID
	 */
	public Map<Integer, String> readCityLocations(InputStream in) {
		BufferedReader read = null;
		String[] fields = null;
		String record = "";
		int cityID = 0;
		int rowNum = 1;
		int cityIDCellNum = 0;
		int continentCellNum = 0;
		int countryCellNum = 0;
		int subdivisionCellNum1 = 0;
		int subdivisionCellNum2 = 0;
		int cityCellNum = 0;
		boolean cityIDCell = false;
		boolean continentCell = false;
		boolean countryCell = false;
		boolean subdivisionCell = false;
		boolean cityCell = false;
		try {
			read = new BufferedReader(new InputStreamReader(in));
			while ((record = read.readLine()) != null) {
				fields = record.split(",");
				if (rowNum == 1) {
					for (int i = 0; i < fields.length; i++) {
						if (fields[i].equals("geoname_id")) {
							cityIDCellNum = i;
							cityIDCell = true;
						} else if (fields[i].equals("continent_name")) {
							continentCellNum = i;
							continentCell = true;
						} else if (fields[i].equals("country_name")) {
							countryCellNum = i;
							countryCell = true;
						} else if (fields[i].equals("subdivision_1_name")) {
							subdivisionCellNum1 = i;
							subdivisionCell = true;
						} else if (fields[i].equals("subdivision_2_name")) {
							subdivisionCellNum2 = i;
							subdivisionCell = true;
						} else if (fields[i].equals("city_name")) {
							cityCellNum = i;
							cityCell = true;
						}
					}
					if (!(cityIDCell && continentCell && countryCell && subdivisionCell && cityCell)) {
						break;
					}
					rowNum++;
				} else {
					if (cityIDCellNum > fields.length) {
						cityID = 0;
					} else {
						cityID = new Double(fields[cityIDCellNum]).intValue();
					}
					if (cityCellNum <= fields.length && !"".equals(fields[cityCellNum])) {
						cityLocationsMap.put(cityID, fields[cityCellNum]);
					} else if (subdivisionCellNum2 <= fields.length && !"".equals(fields[subdivisionCellNum2])) {
						cityLocationsMap.put(cityID, fields[subdivisionCellNum2]);
					} else if (subdivisionCellNum1 <= fields.length && !"".equals(fields[subdivisionCellNum1])) {
						cityLocationsMap.put(cityID, fields[subdivisionCellNum1]);
					} else if (countryCellNum <= fields.length && !"".equals(fields[countryCellNum])) {
						cityLocationsMap.put(cityID, fields[countryCellNum]);
					} else if (continentCellNum <= fields.length && !"".equals(fields[continentCellNum])) {
						cityLocationsMap.put(cityID, fields[continentCellNum]);
					}
					rowNum++;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		System.out.println(cityLocationsName + " 共有" + rowNum + "行");
		return cityLocationsMap;
	}

	/**
	 * 读取IPV4
	 */
	public List<IPV4Info> readIPV4(InputStream in) {
		ISP isp = new ISP();
		IPV4Info ipv4 = new IPV4Info();
		BufferedReader read = null;
		String[] fields = null;
		long[] arr = null;
		String record = "";
		String region = "";
		String ispStr = "";
		String latitude = "";
		String longitude = "";
		int rowNum = 1;
		int ipCellNum = 0;
		int regionCellNum = 0;
		int regionCellNum1 = 0;
		int latitudeCellNum = 0;
		int longitudeCellNum = 0;
		boolean ipCell = false;
		boolean regionCell = false;
		boolean latitudeCell = false;
		boolean longitudeCell = false;
		try {
			read = new BufferedReader(new InputStreamReader(in));
			while ((record = read.readLine()) != null) {
				fields = record.split(",");
				if (rowNum == 1) {
					for (int i = 0; i < fields.length; i++) {
						if (fields[i].equals("network")) {
							ipCellNum = i;
							ipCell = true;
						} else if (fields[i].equals("geoname_id")) {
							regionCellNum = i;
							regionCell = true;
						} else if (fields[i].equals("registered_country_geoname_id")) {
							regionCellNum1 = i;
							regionCell = true;
						} else if (fields[i].equals("latitude")) {
							latitudeCellNum = i;
							latitudeCell = true;
						} else if (fields[i].equals("longitude")) {
							longitudeCellNum = i;
							longitudeCell = true;
						}
					}
					if (!(ipCell && regionCell && latitudeCell && longitudeCell)) {
						break;
					}
					rowNum++;
				} else {
					ipv4 = new IPV4Info();

					if (ipCellNum > fields.length) {
						System.out.println("无IP：" + rowNum);
						break;
					}
					arr = ipMaskToLong(fields[ipCellNum]);
					ipv4.setStartIp(arr[0]);
					ipv4.setEndIp(arr[1]);
					try {
						ispStr =isp.getAddresses(longToIp(arr[1]), "utf-8");
					} catch (Exception e) {
						ispStr = "";
					}
					ipv4.setIsp(ispStr);
					
					if (regionCellNum > fields.length || regionCellNum1 > fields.length) {
						System.out.println("无地域：" + rowNum);
						break;
					}
					region = fields[regionCellNum];
					if ("".equals(region) || region == null) {
						region = fields[regionCellNum1];
						if ("".equals(region) || region == null) {
							break;
						}
					}
					ipv4.setRegion(cityLocationsMap.get(new Double(region).intValue()));

					if (latitudeCellNum > fields.length) {
						latitude = "0";
					} else {
						latitude = fields[latitudeCellNum];
					}
					ipv4.setLatitude(Double.parseDouble(latitude));

					if (longitudeCellNum > fields.length) {
						longitude = "0";
					} else {
						longitude = fields[longitudeCellNum];
					}
					ipv4.setLongitude(Double.parseDouble(longitude));

					ipv4List.add(ipv4);

					rowNum++;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		System.out.println(IPV4Name + " 共有" + rowNum + "行");
		return ipv4List;
	}

	/**
	 * 输出数据
	 * 
	 * @throws IOException
	 */
	public void outTxt(String path) {
		StringBuffer buf = new StringBuffer();
		buf.append("0 0 0 IANA保留地址 纬度 经度");
		buf.append("\r\n");
		for (int i = 0; i < ipv4List.size(); i++) {
			buf.append(ipv4List.get(i).getStartIp() + " " + ipv4List.get(i).getRegionId() + " "
					+ ipv4List.get(i).getIspId() + " " + ipv4List.get(i).getRegion() + " "
					+ ipv4List.get(i).getIsp() + " " + ipv4List.get(i).getLatitude() + " "
					+ ipv4List.get(i).getLongitude());
			buf.append("\r\n");
			buf.append(ipv4List.get(i).getEndIp() + " " + ipv4List.get(i).getRegionId() + " "
					+ ipv4List.get(i).getIspId() + " " + ipv4List.get(i).getRegion() + " "
					+ ipv4List.get(i).getIsp() + " " + ipv4List.get(i).getLatitude() + " "
					+ ipv4List.get(i).getLongitude());
			buf.append("\r\n");
		}
		File file = new File(path);
		try {
			// 保存文件到硬盘
			if (!file.exists()) {
				file.createNewFile(); // 创建新文件
			}
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "utf-8"));
			bw.write(buf.toString());
			bw.flush();
			bw.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * ip带掩码转数字段
	 * 
	 * @param ipAddress
	 * @return
	 */
	public long[] ipMaskToLong(String ipAndMask) {
		String[] ipArr = ipAndMask.split("/");
		if (ipArr.length != 2) {
			throw new IllegalArgumentException("invalid ipAndMask with: " + ipAndMask);
		}
		int netMask = Integer.valueOf(ipArr[1].trim());
		if (netMask <= 0 || netMask > 32) {
			throw new IllegalArgumentException("invalid ipAndMask with: " + ipAndMask);
		}

		long ipInt = ipToLong(ipArr[0]);
		if (netMask == 32) {
			return new long[] { ipInt, ipInt };
		} else {
			long netIP = ipInt & (0xFFFFFFFF << (32 - netMask));
			long hostScope = (0xFFFFFFFF >>> netMask);
			return new long[] { netIP, netIP + hostScope };
		}
	}

	/**
	 * ip转数字
	 * 
	 * @param ipAddress
	 * @return
	 */
	public long ipToLong(String ipAddress) {
		long result = 0;
		String[] ipAddressInArray = ipAddress.split("\\.");
		for (int i = 3; i >= 0; i--) {
			long ip = Long.parseLong(ipAddressInArray[3 - i]);
			result |= ip << (i * 8);
		}
		return result;
	}

	/**
	 * 数字转ip
	 * 
	 * @param ipAddress
	 * @return
	 */
	public static String longToIp(long ip) {
		StringBuilder result = new StringBuilder(15);
		for (int i = 0; i < 4; i++) {
			result.insert(0, Long.toString(ip & 0xff));
			if (i < 3) {
				result.insert(0, '.');
			}
			ip = ip >> 8;
		}
		return result.toString();
	}

}
